//============================================================================
// Name        : RecordServer.cpp
// Author      : liangjin
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <stdio.h>
//#include "udt.h"
#include "string.h"
#include<sys/types.h>
#include<sys/socket.h>
#include <unistd.h>
#include <sys/stat.h>
#include<netinet/in.h>


#define MAX_USER_NUM 2
int g_RecordLinstenSock;//侦听CMA上传录像文件的套接字
int g_ClientLinstenSock;//侦听NetClient的套接字
User g_user[MAX_USER_NUM];
ClientUser g_ClientUser[MAX_USER_NUM];

//NetClient消息处理线程
void* threadClientRecv(void* p)
{
	ClientUser* user = (ClientUser*)p;
	char RecvBuf[2048*6];
	int MsgLen;
	fd_set fdSocket;

    timeval tv;

	while(1)
	{
		  //  printf("user recv thread start,userHandle=%d,sock=%d\n",user->GetUserHandle(),user->m_CommandSock);
	        if(-1 == user->GetUserHandle() || -1 == user->m_sock)
	        {
	        	printf("recv thread break,userhandle = %d,m_sock = %d\n",user->GetUserHandle(),user->m_sock);
	        	break;
	        }
	        FD_ZERO(&fdSocket);
	        FD_SET(user->m_sock,&fdSocket);
	       // printf("recv select start\n");
	        timeval tv;
	        tv.tv_sec = 2;
	        tv.tv_usec = 0;
	        int iRet = ::select(user->m_sock+1,&fdSocket,NULL,NULL,&tv);
	       // printf("recv select stop,ret = %d\n",iRet);
            if(0 == iRet)
            {
            	continue;
            }
            else if(0 > iRet)
            {
            	perror("select");
            	break;
            }
            else
            {
            	//printf("user recv start\n");
    	        MsgLen = recv(user->m_sock,RecvBuf,sizeof(RecvBuf),0);
    	        if(0 >= MsgLen)
    	        {
    	        	continue;
    	        }
    	       // printf("user recv message suceful,the message len = %d,the sock = %d\n",MsgLen);
    		    user->ProcessMsg(&(user->m_sock),RecvBuf, MsgLen);
            }

	}
	printf("user recv thread exit\n");
}
//CMA消息处理线程
void* threadCMARecv(void* p)
{
	User* user = (User*)p;
	if(user == NULL)
	{
		return NULL;
	}
    user->RecvMsg();
}
//CMA消息处理函数
void* threadCMAMsgFun(void* p)
{
	int optval = 1;
	struct sockaddr_in AddrListen;

	g_RecordLinstenSock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if(-1 == g_RecordLinstenSock)
	{
		printf("create socket failed\n");
		return NULL;
	}
	memset (&AddrListen, 0, sizeof (struct sockaddr_in));
	AddrListen.sin_family = AF_INET;
	AddrListen.sin_port = htons (6000);//ListenPort
	AddrListen.sin_addr.s_addr = INADDR_ANY;

	setsockopt (g_RecordLinstenSock, SOL_SOCKET, SO_REUSEADDR, (char *) &optval,
				sizeof (int));

	if (bind(g_RecordLinstenSock, (struct sockaddr *) &AddrListen,sizeof (struct sockaddr_in)) < 0)
	  {
		  perror ("bind");
		  close (g_RecordLinstenSock);
		  return NULL;
	  }
	//最多接收两路CMA同时上传
	listen(g_RecordLinstenSock,2);


	printf("CMA Msg accept thread start\n");
    int recvSock;
    struct sockaddr_in AddrRecv;
    socklen_t structlen = sizeof (struct sockaddr_in);
    int i,ret;
    fd_set fdSocket;

    timeval tv;
    while(1)
    {
    	FD_ZERO(&fdSocket);
    	FD_SET(g_RecordLinstenSock,&fdSocket);
    	//printf("select start,the sock = %d\n",g_RecordLinstenSock);


        tv.tv_sec = 20;
        tv.tv_usec = 0;
        printf("CMA Msg select start\n");
    	int nRet = ::select(g_RecordLinstenSock+1,&fdSocket,NULL,NULL,&tv);
    	printf ("CMA Msg select return %d\n",nRet);
    	if(0 == nRet)
    	{
    		continue;
    	}
    	if(nRet > 0)
    	{
   	     if(FD_ISSET(g_RecordLinstenSock,&fdSocket))
   		 {
            recvSock = accept(g_RecordLinstenSock,(struct sockaddr *)&AddrRecv,&structlen);
            if(-1 == recvSock)
            {
            	printf("accept failed\n");
            	continue;
            }
            printf("CMA Msg accept suceful,the recvSock=%d\n",recvSock );
            int i;
            for(i=0;i<MAX_USER_NUM;i++)
            {
                if(-1==g_user[i].m_sock)
            	{
            		break;
            	}
            }
            MSG_RESULT msgResult;
        	msgResult.msgHead.iCmdType = MSG_RECORD_SERVER_CONNECTSTATE;
        	msgResult.msgHead.iMsgSize = sizeof(MSG_RESULT);
            if(i == MAX_USER_NUM)
            {
            	//通知客户端，服务器连接已经达到上限
            	msgResult.iRet = 0;
            	nRet = send(recvSock,&msgResult,sizeof(MSG_RESULT),0);
            	printf("send result return %d\n",nRet);
            	continue;
            }
            else
            {
            	printf("CMA Msg user index is %d\n",i);

            	msgResult.iRet = 1;
            	nRet = send(recvSock,&msgResult,sizeof(MSG_RESULT),0);
            	printf("send result return %d\n",nRet);

            	g_user[i].m_sock = recvSock;
                g_user[i].InitUserState();
                g_user[i].SetAddr(AddrRecv.sin_addr.s_addr);
                pthread_attr_t attr = {0};
                pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
                nRet = pthread_create(&(g_user[i].m_recvPt),&attr,threadCMARecv,&(g_user[i]));
               // g_user[i].ProcessMsg();
            }
   		 }
    	}
    }
}
//侦听CMA录像上传线程
void* threadCMARecordFun(void* p)
{
    printf("CMARecord accept thread start\n");
	int optval = 1;
        int ListenSocket;
        int RecordSocket;
	struct sockaddr_in AddrListen;
	struct sockaddr_in AddrRecv;
	struct timeval timeout;
	/*read data from this ListenPort ,read from server.cfg */
	int ListenPort;

	ListenSocket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (ListenSocket < 0)
	{
		  printf ("CMARecord thread :Create ListenSocket error\n");
		  return NULL;
	}
	//netSdk->SetStreamListenSock(ListenSocket);
	memset (&AddrListen, 0, sizeof (struct sockaddr_in));
	AddrListen.sin_family = AF_INET;
	AddrListen.sin_port = htons (6600);
	AddrListen.sin_addr.s_addr = INADDR_ANY;

	setsockopt (ListenSocket, SOL_SOCKET, SO_REUSEADDR, (char *) &optval,
				sizeof (int));

	printf("CMARecord thread : bind socket\n");
	if (bind(ListenSocket, (struct sockaddr *) &AddrListen,sizeof (struct sockaddr_in)) < 0)
	  {
		  perror ("bind");
		  close (ListenSocket);
		  return NULL;
	  }
	listen(ListenSocket, 2);//netSdk->GetStreamListenSock()
    socklen_t structlen = sizeof (struct sockaddr_in);
    int MsgLen;
    int i;
    fd_set fdSocket;

    while(1)
    {
    	FD_ZERO(&fdSocket);
    	FD_SET(ListenSocket,&fdSocket);
    	printf("CMARecord select start\n");

        timeval tv;
        tv.tv_sec = 5;
        tv.tv_usec = 0;

    	int nRet = ::select(ListenSocket+1,&fdSocket,NULL,NULL,&tv);
    	printf ("CMARecord select return %d\n",nRet);
    	if(0 == nRet)
    	{
    		continue;
    	}

    	if(nRet > 0)
    	{
      	     if(FD_ISSET(ListenSocket,&fdSocket))
      		 {
      			printf("CMARecord thread : accept start\n");
      			RecordSocket =accept (ListenSocket, (struct sockaddr *) &AddrRecv, &structlen);
      			if(-1 == RecordSocket)
      			{
      				printf("CMARecord thread accept: fail!\n");
      				return NULL;
      			}
      			printf("CMARecord accept suceful,the sock = %d\n",RecordSocket);
      	        for(i = 0;i < MAX_USER_NUM;i++)
      	        {
      	        	if(g_user[i].getAddr() == AddrRecv.sin_addr.s_addr)
      	        	{
      	                 break;
      	        	}
      	        }
      	        g_user[i].m_Recordsock = RecordSocket;
      	        //g_ClientUser[i].m_downFileSock = DownFileSocket;
      		    //printf("Down file thread thread : user[%d] stream sock accept succesful,the streamSocket = %d\n",i,DownFileSocket);
      		 }
    	}
    }
}
void* threadClientFun(void* p)
{

	int optval = 1;
	struct sockaddr_in AddrListen;
	socklen_t structlen = sizeof (struct sockaddr_in);

	g_ClientLinstenSock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if(-1 == g_ClientLinstenSock)
	{
		printf("create socket failed\n");
		return NULL;
	}
	memset (&AddrListen, 0, sizeof (struct sockaddr_in));
	AddrListen.sin_family = AF_INET;
	AddrListen.sin_port = htons (7000);//ListenPort
	AddrListen.sin_addr.s_addr = INADDR_ANY;

	setsockopt (g_ClientLinstenSock, SOL_SOCKET, SO_REUSEADDR, (char *) &optval,
				sizeof (int));

	if (bind(g_ClientLinstenSock, (struct sockaddr *) &AddrListen,sizeof (struct sockaddr_in)) < 0)
	  {
		  perror ("bind");
		  close (g_ClientLinstenSock);
		  return NULL;
	  }
	listen(g_ClientLinstenSock,10);

	//printf("client accept thread start\n");
    int recvSock;
    struct sockaddr_in AddrRecv;
    //socklen_t structlen = sizeof (struct sockaddr_in);
    int i,ret;
    fd_set fdSocket;

    while(1)
    {
    	FD_ZERO(&fdSocket);
    	FD_SET(g_ClientLinstenSock,&fdSocket);
    	//printf("client select start\n");

        timeval tv;
        tv.tv_sec = 5;
        tv.tv_usec = 0;

    	int nRet = ::select(g_ClientLinstenSock+1,&fdSocket,NULL,NULL,&tv);
    	//printf ("client select return %d\n",nRet);
    	if(0 == nRet)
    	{
    		continue;
    	}
    	if(nRet > 0)
    	{
   	     if(FD_ISSET(g_ClientLinstenSock,&fdSocket))
   		 {
            recvSock = accept(g_ClientLinstenSock,(struct sockaddr *)&AddrRecv,&structlen);
            if(-1 == recvSock)
            {
            	printf("accept failed\n");
            	continue;
            }
          //  printf("accept suceful,the recvSock=%d\n",recvSock );
            int i;
            for(i=0;i<MAX_USER_NUM;i++)
            {
            	if(g_ClientUser[i].m_bUse == false)
            	{
            		break;
            	}
            }
            if(i == MAX_USER_NUM)
            {
            	//通知客户端，服务器连接已经达到上限
            	continue;
            }
            else
            {
            	g_ClientUser[i].m_sock = recvSock;
            	g_ClientUser[i].SetUserHandle(i);
            	g_ClientUser[i].SetAddr(AddrRecv.sin_addr.s_addr);
            	nRet = pthread_create(&(g_ClientUser[i].m_recvPt),NULL,threadClientRecv,&(g_ClientUser[i]));
            	if(0 == nRet)
            	{
            		g_ClientUser[i].m_bConnect = true;
            	}
            }
   		 }
    	}
    }
}
//侦听NetClient下载录像的链接
void* threadClientDown(void* p)
{
   // printf("threadClientDown start\n");
	int optval = 1;
        int ListenSocket;
        int DownFileSocket;
	struct sockaddr_in AddrListen;
	struct sockaddr_in AddrRecv;
	struct timeval timeout;
	/*read data from this ListenPort ,read from server.cfg */
	int ListenPort;

	ListenSocket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (ListenSocket < 0)
	{
		  printf ("Down file thread :Create ListenSocket error\n");
		  return NULL;
	}
	//netSdk->SetStreamListenSock(ListenSocket);
	memset (&AddrListen, 0, sizeof (struct sockaddr_in));
	AddrListen.sin_family = AF_INET;
	AddrListen.sin_port = htons (7100);
	AddrListen.sin_addr.s_addr = INADDR_ANY;

	setsockopt (ListenSocket, SOL_SOCKET, SO_REUSEADDR, (char *) &optval,
				sizeof (int));

	//printf("Down file thread : bind socket\n");
	if (bind(ListenSocket, (struct sockaddr *) &AddrListen,sizeof (struct sockaddr_in)) < 0)
	  {
		  perror ("bind");
		  close (ListenSocket);
		  return NULL;
	  }
	listen(ListenSocket, 10);//netSdk->GetStreamListenSock()
    socklen_t structlen = sizeof (struct sockaddr_in);
    int MsgLen;
    int i;
    fd_set fdSocket;

    while(1)
    {
    	FD_ZERO(&fdSocket);
    	FD_SET(ListenSocket,&fdSocket);
    	//printf("downfile select start\n");

        timeval tv;
        tv.tv_sec = 5;
        tv.tv_usec = 0;

    	int nRet = ::select(ListenSocket+1,&fdSocket,NULL,NULL,&tv);
    	//printf ("downfile select return %d\n",nRet);
    	if(0 == nRet)
    	{
    		continue;
    	}

    	if(nRet > 0)
    	{
      	     if(FD_ISSET(ListenSocket,&fdSocket))
      		 {
      			//printf("Down file thread : accept start\n");
      			DownFileSocket =accept (ListenSocket, (struct sockaddr *) &AddrRecv, &structlen);
      			//printf("Dwon file accept suceful,the sock = %d\n",DownFileSocket);
      			if(-1 == DownFileSocket)
      			{
      				printf("Down file thread accept: fail!\n");
      				return NULL;
      			}
      	        for(i = 0;i < MAX_USER_NUM;i++)
      	        {
      	        	if(g_ClientUser[i].getAddr() == AddrRecv.sin_addr.s_addr)
      	        	{
      	                 break;
      	        	}
      	        }
      	        g_ClientUser[i].m_downFileSock = DownFileSocket;
      		    //printf("Down file thread thread : user[%d] stream sock accept succesful,the streamSocket = %d\n",i,DownFileSocket);
      		 }
    	}
    }
}
int main()
{
    ThreadX threadCMAMsgAccept,threadCMARecord,threadClientAccept,threadClientDownAccept;
    //CMA消息处理线程
    threadCMAMsgAccept.startThread(&threadCMAMsgFun,NULL);
    //侦听CMA上传录像的线程
    threadCMARecord.startThread(&threadCMARecordFun,NULL);
    //NetClient消息处理线程
    threadClientAccept.startThread(&threadClientFun,NULL);
    //NetClient下载录像线程
    threadClientDownAccept.startThread(&threadClientDown,NULL);
    threadCMAMsgAccept.joinThread(NULL);
    printf("exit11111111111111\n");
	return 0;
}
